
#include "precompiled.h"
#include "zones.h"

#include <QtCore>

#include "configstack.h"

#include "helper.h"
#include <logger/logger.h>
#include <config/configfile.h>
#include "engine.h"

#include <qjson/parser.h>

#include "script/objects/optra.h"

#include "script/contextimpl.h"
#include <extensions/zoneinterface.h>
#include "windowsmanager.h"

class ZonesPrivate{
public:
    ZonesPrivate() {}
    ~ZonesPrivate() {}
    Zones::ZonesInterfaces zoneInterf;
    QList<Opl::Core::EntityObject*> zoneslist;


};

Zones::Zones(Opl::Core::EntityObject *parent) :
    Opl::Core::EntityObject(parent), O_PRIVATE_CREATE(Zones)
{
}

Zones::~Zones()
{
    O_PRIVATE_DELETE;
}


Zones::ZonesInterfaces Zones::interfaces()const
{
    O_C(Zones);
    return d->zoneInterf;
}

QDeclarativeListProperty<Opl::Core::EntityObject> Zones::zones()
{
    O_D(Zones);
    //return QDeclarativeListProperty<TaskEntry>(this, 0, Tasks::child_append);
    return QDeclarativeListProperty<Opl::Core::EntityObject>(this, d->zoneslist);
}


bool Zones::loadZone(Optra::Extensions::Context* ctx)
{
    Q_ASSERT(ctx);

    O_D(Zones);

    QString binPattern;
    if (ctx->config()){
        binPattern= ctx->config()->value("global", "entry", "").toString();
    }

    if (binPattern.isEmpty()){
        binPattern = "$BINDIR/" + ctx->rootDir().dirName();
    }
    QString path =  Engine::instance()->environment()->expandPath(binPattern, ctx);

#if defined (Q_WS_WIN)
    path += ".dll";
#elif (Q_WS_X11)
    path += ".so";
#endif

    LI.Debug() << "Loading zone:" << path;
    QPluginLoader pluginLoader(path);
    QObject *plugin = pluginLoader.instance();
    if (plugin){
        Optra::Extensions::ZoneInterface* interface = qobject_cast<Optra::Extensions::ZoneInterface *>(plugin);
        if (!interface){
            LI.Warning() << "Invalid plugind interface";
            return false;
        }

        ctx->setInterface(interface);
        LI.Debug()
                << "\tName: "
                << interface->name()
                << " Context: " << ctx->toString();

        interface->setContext(ctx);

        d->zoneInterf.append(interface);
        d->zoneslist.append(interface->object());
        return true;
    }else{
        LI.Warning() << "Failed loading: " << ctx->toString() << " error:" << pluginLoader.errorString();
        return false;
    }
}

void Zones::processDirectory(QDir dir)
{

    LI.Debug() << "Process dir: " << dir.absolutePath();
    if (!dir.exists())
    {
        LI.Error() << "Dir: " << dir.absolutePath() << " don't exists";
        return;
    }

    Optra::Extensions::Context* context = new ContextImpl;

    context->setBridge(new OptraCore(0, context));
    context->process(dir, true);
    if (!loadZone(context))
        delete context;

}

void Zones::loadZones()
{
    O_D(Zones);

    LI.Info() << "Loading Zones";

    QDir zonesDir(qApp->applicationDirPath());
    zonesDir.cd("zones");
    foreach (QString dirname, zonesDir.entryList(QStringList() <<  "*", QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable)) {
        zonesDir.cd(dirname);
        processDirectory(zonesDir);
        zonesDir.cdUp();
    }
}

void Zones::finalizeZone(Optra::Extensions::ZoneInterface* inf)
{
    Q_ASSERT(inf);

    LI.Info() << "Finalize zone:" << inf->name();
    inf->finalize();
    Engine::instance()->windowsManager()->removeWindows(inf);
    Optra::Extensions::Context* ctx = inf->context();
    ctx->config()->save();
}

void Zones::finalizeZones()
{
    O_D(Zones);
    foreach(Optra::Extensions::ZoneInterface* interface, d->zoneInterf){
        finalizeZone(interface);
    }
}

bool Zones::isZoneLoaded(QString& name)
{
    O_D(Zones);
	return false;
}

bool Zones::isZoneActive(QString& name)
{
    O_D(Zones);
	return false;
}

void Zones::initializeZones()
{
    O_D(Zones);
    foreach(Optra::Extensions::ZoneInterface* interface, d->zoneInterf){
        LI.Info() << "Iniatlize zone:" << interface->name();
        interface->initialize();
    }
}


void Zones::install(const QString& path)
{
    O_D(Zones);
    Q_UNUSED(path);
    LI.Warning() << "TO_BE_IMPLEMENTED:Install Zone ";
}
